package com.example.routeplansystem.service.impl;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.Objects;

import javax.imageio.ImageIO;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import com.example.routeplansystem.constant.Constant;
import com.example.routeplansystem.constant.CookieMessage;
import com.example.routeplansystem.constant.ManagerOperationType;
import com.example.routeplansystem.constant.ResponseMessage;
import com.example.routeplansystem.constant.ResponseStatus;
import com.example.routeplansystem.constant.SessionMessage;
import com.example.routeplansystem.dao.UserDao;
import com.example.routeplansystem.entity.dto.ResponseEntity;
import com.example.routeplansystem.entity.po.UserMessage;
import com.example.routeplansystem.entity.vo.UserInfo;
import com.example.routeplansystem.service.UserService;
import com.example.routeplansystem.utils.DateUtil;
import com.example.routeplansystem.utils.EncryptionUtil;
import com.example.routeplansystem.utils.MailUtil;
import com.example.routeplansystem.utils.VerifyCodeImageUtil;

import lombok.extern.slf4j.Slf4j;


//用户Service层
@Service
@Configuration
@Slf4j
@Import(value = MailSenderAutoConfiguration.class)
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private JavaMailSender mailSender; //JavaMailSender由Spring提供的邮件发送

    public static final Integer COMMON_USER_ROLE = 0;

    //用户登录
    @Override
    public ResponseEntity<UserMessage> userLogin(UserInfo userInfo, HttpServletRequest request, HttpServletResponse response) {

        //解析，获取用户信息：
        String userName = userInfo.getUserMessage().getUserName();
        String password = userInfo.getUserMessage().getPassword();
        int role = userInfo.getUserMessage().getRole();
        String code = userInfo.getCode();

        log.info("------- 用户名：" + userName + "\t密码：" + password + "------" + DateUtil.getFormatDate());

        //获取Session
        HttpSession session = request.getSession();

        //验证动态验证码信息：
        try {
            checkVerifyCode(code, session);
        } catch (Exception e) {
            //捕获到异常登录失败，返回异常信息：
            return new ResponseEntity<>(ResponseStatus.FAILURE_RESPONSE, e.getMessage(), null);
        }

        //查询数据库：
        UserMessage userMessageFromDB = userDao.selectUserByUserName(userName);

        if (null != userMessageFromDB) {
            log.info("------数据库查询：" + userMessageFromDB + "------");

            try {
                //验证用户信息：
                checkUserMessage(password, userMessageFromDB,role);
            } catch (Exception e) {
                //捕获到异常登录失败，返回异常信息：
                return new ResponseEntity<>(ResponseStatus.FAILURE_RESPONSE, e.getMessage(), null);
            }

            //用户信息存入Session：
            session.setAttribute(SessionMessage.USER_ID_KEY, userMessageFromDB.getUserId());    //用户id
            session.setAttribute(SessionMessage.LOGIN_KEY, SessionMessage.LOGIN_ATTRIBUTE);     //登录状态

            //用户信息存入Cookie，响应给前端：
            addCookie(session, response, userName, password);

            return new ResponseEntity<>(ResponseStatus.SUCCESS_RESPONSE, ResponseMessage.LOGIN_SUCCESSFULLY, userMessageFromDB);
        } else {
            return new ResponseEntity<>(ResponseStatus.FAILURE_RESPONSE, "当前用户未注册！！！", null);
        }
    }

    //验证动态验证码：
    private void checkVerifyCode(String code, HttpSession session) throws RuntimeException {
        String verifyCode = (String) session.getAttribute(SessionMessage.CODE_KEY);
        if (verifyCode == null) {
            throw new RuntimeException("请先获取验证码图片！！！");
        }
        if (!code.equalsIgnoreCase(verifyCode)) {
            throw new RuntimeException("验证码有误！！！");
        }
    }

    //校验用户信息：
    private void checkUserMessage(String password, UserMessage userMessage, int role) throws RuntimeException {
        if (null == userMessage || !password.equals(userMessage.getPassword())) {
            throw new RuntimeException("请检查用户名或者密码是否正确！！！");
        }
        checkUserRole(role, userMessage);
    }

    //校验用户权限
    private void checkUserRole(int role, UserMessage userMessage) throws RuntimeException {
        if (role != userMessage.getRole()) {
            throw new RuntimeException("用户权限错误！！！");
        }
    }

    //用户信息存入Cookie：
    private void addCookie(HttpSession session, HttpServletResponse response, String userName, String password) {
        Cookie userNameCookie = new Cookie(CookieMessage.USER_NAME, userName);
        Cookie passwordCookie = new Cookie(CookieMessage.PASSWORD, password);
        //将Session的Id(JSESSIONID)，响应给前端：
        Cookie sessionId = new Cookie("JSESSIONID", session.getId());

        response.addCookie(sessionId);
        response.addCookie(userNameCookie);
        response.addCookie(passwordCookie);
    }

    //生成动态验证码：
    @Override
    public void generateVerifyCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //生成动态验证码：（Object[0]：验证码字符串；Object[1]：验证码图片）
        Object[] objs = VerifyCodeImageUtil.createImage();

        log.info("------生成动态验证证码：" + objs[0] + "------" + DateUtil.getFormatDate());

        //在Session中保存动态验证码信息：
        request.getSession().setAttribute(SessionMessage.CODE_KEY, objs[0]);

        HttpSession session = request.getSession();
        //将Session的Id(JSESSIONID)，响应给前端：
        Cookie sessionId = new Cookie("JSESSIONID", session.getId());
        response.addCookie(sessionId);

        //获取到动态生成的验证码图片：
        BufferedImage image = (BufferedImage) objs[1];
        //response的setContentType() 方法用于设置发送到客户端的响应的内容类型
        response.setContentType("image/png");
        OutputStream os = response.getOutputStream();
        //写出动态生成的验证码图片：
        ImageIO.write(image, "png", os);
    }

    //用户注册：
    @Override
    public ResponseEntity<UserMessage> userRegister(UserInfo userInfo, HttpServletRequest request, HttpSession session) {

        //获取用户信息和邮箱验证码：
        UserMessage userMessage = userInfo.getUserMessage();
        String mailCode = userInfo.getCode();

        log.info("------" + userInfo.getUserMessage().toString() + "------" + DateUtil.getFormatDate());

        try {
            //邮箱验证码校验：
            checkMailCode(mailCode, session);
        } catch (RuntimeException e) {
            return new ResponseEntity<>(ResponseStatus.FAILURE_RESPONSE, e.getMessage(), null);
        }

        try {
            //用户名邮箱验重：
            checkDuplicate(userMessage);
        } catch (Exception e){
            return new ResponseEntity<>(ResponseStatus.FAILURE_RESPONSE, e.getMessage(), null);
        }


        //数据库操作：
        boolean flag = userDao.insertUser(userMessage);

        log.info("------用户注册成功?" + flag + "------" + DateUtil.getFormatDate());

        //移除邮箱验证码：
        session.removeAttribute(SessionMessage.MAIL_CODE_KEY);

        return new ResponseEntity<>(ResponseStatus.SUCCESS_RESPONSE, ResponseMessage.REGISTERED_SUCCESSFULLY, null);
    }

    //邮箱验证码校验：
    private void checkMailCode(String code, HttpSession session) throws RuntimeException {

        log.info("------前端提交登录验证码：" + code + "-------" + DateUtil.getFormatDate());

        //从Session中获取邮箱验证码：
        String mailVerifyCode = (String) session.getAttribute(SessionMessage.MAIL_CODE_KEY);

        log.info("------session中的邮箱验证码 " + mailVerifyCode + "------" + DateUtil.getFormatDate());

        if (!Objects.equals(mailVerifyCode, code)) {
            throw new RuntimeException("邮箱验证码错！！！");
        }
    }

    //用户名邮箱验重：
    public void checkDuplicate(UserMessage userMessage) throws RuntimeException {
        UserMessage userMessageFromDB1 = userDao.selectUserByUserName(userMessage.getUserName());
        if (userMessageFromDB1 != null) {
            throw new RuntimeException("用户名已经被注册，请尝试登录！！！");
        }
        UserMessage userMessageFromDB2 = userDao.userEmail(userMessage.getEmail());
        if (userMessageFromDB2 != null) {
            throw new RuntimeException("邮箱已经被注册，请尝试登录！！！");
        }
    }

    //邮箱验证码：
    @Override
    public ResponseEntity<String> sendVerifyMail(String eMail, HttpServletRequest request, HttpServletResponse response) {
        //生成验证码：
        String mailCode = MailUtil.generateRandomMailCode();

        HttpSession session = request.getSession();
        session.setAttribute(SessionMessage.MAIL_CODE_KEY, mailCode);
        //将Session的Id(JSESSIONID)，响应给前端：
        Cookie sessionId = new Cookie("JSESSIONID", session.getId());
        response.addCookie(sessionId);

        try {
            //发送验证码：
            sendMailCodeMail(eMail, mailCode);
        } catch (Exception e) {
            return new ResponseEntity<>(ResponseStatus.FAILURE_RESPONSE, e.getMessage(), null);
        }

        return new ResponseEntity<>(ResponseStatus.SUCCESS_RESPONSE, ResponseMessage.CODE_SEND_SUCCESSFULLY, null);
    }

    //发送验证码：
    public void sendMailCodeMail(String eMail, String mailCode) throws MessagingException {

        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);

        helper.setFrom(Constant.EMAIL_FROM);
        helper.setTo(eMail);
        helper.setSubject("Path Security");

        String sb = "<div style='position: relative; margin: 0 auto; width: 450px;height: 350px;'>" +
                "<h1 align='center'><strong>Path</strong></h1>" +
                "<h5>您好：</h5>" +
                "<h5>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎您通过邮箱验证码来验证您的身份！</h5>" +
                "<h5>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;快！使用<div style='position: relative; " +
                "margin: 0 auto; width: 100px;height: 45px; text-align: center; background-color: #EEE'>" +
                "<font size='5' style='position: relative; top: 6px;'>"
                + mailCode
                + "</font></div>去验证您的身份吧！切记不要告诉他人哦！</h5>" +
                "<h5 style='position:relative; float: right; margin-bottom: 0'>Path</h5><br><br>" +
                "<h5 style='position: relative; float: right; margin-top: 0'>" + DateUtil.getFormatDate() + "</h5></div>";
        helper.setText(sb, true);

        mailSender.send(message);
    }

    //用户注销登录：
    @Override
    public ResponseEntity<String> loginOut(HttpServletRequest request) {

        //清除客户端Cookie：
        deleteCookies(request);
        HttpSession session = request.getSession();
        session.removeAttribute(SessionMessage.LOGIN_KEY);
        session.invalidate();

        return new ResponseEntity<>(ResponseStatus.SUCCESS_RESPONSE, ResponseMessage.CANCELLATION_OF_SUCCESS, null);
    }

    //循环清除Cookie：
    private void deleteCookies(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(CookieMessage.USER_NAME)
                    || cookie.getName().equals(CookieMessage.PASSWORD)) {
                cookie.setMaxAge(0);
            }
        }
    }

    //用户自动登录：
    @Override
    public boolean autoLogin(HttpServletRequest request) {
        return autoLoginBySession(request.getSession()) || autoLoginByCookie(request);
    }

    @Override
    public ResponseEntity<List<UserMessage>> selectUsersByRole(int role) {
        return new ResponseEntity<>(ResponseStatus.SUCCESS_RESPONSE, ResponseMessage.CANCELLATION_OF_SUCCESS,
                userDao.selectUsersByRole(role));
    }

    public ResponseEntity manageUser(UserMessage userMessage, Integer operationType) {
        boolean flag = true;
        try {
            if (Objects.equals(ManagerOperationType.ADD.operationType, operationType)) {
                flag = userDao.insertUser(userMessage);
            } else if (Objects.equals(ManagerOperationType.DELETE.operationType, operationType)) {
                flag = userDao.deleteUserById(userMessage.getUserId());
            } else if (Objects.equals(ManagerOperationType.UPDATE.operationType, operationType)) {
                flag = userDao.updateUserById(userMessage);
            }
        } catch (DuplicateKeyException e) {
            return new ResponseEntity(ResponseStatus.FAILURE_RESPONSE, "操作失败，请注意用户名，邮箱不能重复", null);
        }
        if (!flag) {
            return new ResponseEntity(ResponseStatus.FAILURE_RESPONSE, "操作失败,请重试", null);
        }
        return new ResponseEntity(ResponseStatus.SUCCESS_RESPONSE, null,
                userDao.selectUsersByRole(COMMON_USER_ROLE));
    }

    private boolean autoLoginBySession(HttpSession session) {
        return session.getAttribute(SessionMessage.LOGIN_KEY) != null;
    }

    private boolean autoLoginByCookie(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        String userName = null;
        String password = null;
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(CookieMessage.USER_NAME)) {
                userName = cookie.getValue();
            }
            if (cookie.getName().equals(CookieMessage.PASSWORD)) {
                password = cookie.getValue();
            }
        }

        if (userName == null || password == null) {
            return false;
        }
        UserMessage userMessage = userDao.selectUserByUserName(userName);
        if (userMessage.getPassword().equals(EncryptionUtil.md5(password))) {
            request.getSession().setAttribute(SessionMessage.LOGIN_KEY, SessionMessage.LOGIN_ATTRIBUTE);
            return true;
        }
        return false;
    }
}
